package com.swa99ylum.pxf.cell.adhesive;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;

import org.apache.poi.xssf.usermodel.XSSFCell;

import com.swa99ylum.pxf.util.MergedRegionUtils;


/**
 * 粘合剂：用于 合并单元格。具有 "横向黏连"、"纵向黏连" 这 2 个 维度的 "黏连能力"
 * 
 * @author lsy
 */
public class Adhesive {
	

	/*--------------------------------------------
    |      				内部类			         |
    ============================================*/
	
	/**
	 * 【内部类】：粘合剂 的 "黏连维度"
	 * <br> 每个"黏连维度" 都有 "排除列表"，粘合剂 不会对 "排除列表" 中的 项，触发 黏连操作
	 * 
	 * @author lsy
	 */
	public class Dimension {
		/**
		 * 排除列表：
		 * <br> 虽然定义的 是 Object[]，但由于 exclusionList.contains(ele) 时 使用的是 == 来进行比较，所以 "排除功能"
		 * <br> 1) 只对 "基本类型"、"String" 生效
		 * <br> 2) 不对 "引用类型" 生效，把 "引用类型" 放入 exclusions 中，是 没有意义的
		 */
		private Object[] exclusions;
		
		@Override
		public String toString() {
			return "Dimension [exclusions=" + Arrays.toString(exclusions) + "]";
		}

		/**
		 * 构造器
		 * @param exclusions : 排除列表，粘合剂 不会对 "排除列表" 中的 项，触发 黏连操作
		 */
		public Dimension(Object[] exclusions) {
			super();
			this.exclusions = exclusions;
		}

		//getter、setter
		public Object[] getExclusions() {
			return exclusions;
		}

		public void setExclusions(Object[] exclusions) {
			this.exclusions = exclusions;
		}
	}
	
	
	
	/*--------------------------------------------
    |      				成员变量			         |
    ============================================*/
	
	/**
	 * 横向 粘合剂
	 */
	private Dimension hizAdhesive;	//horizontal	横向维度
	
	/**
	 * 纵向 粘合剂
	 */
	private Dimension vetAdhesive;	//vertical 		纵向维度

	
	
	/*--------------------------------------------
    |      			横向黏连、纵向黏连		         |
    ============================================*/
	
	/**
	 * 是否拥有 "横向 粘合剂"
	 */
	public boolean hasHizAdhesive() {
		if(hizAdhesive != null)	return true;
		else					return false;
	}
	
	/**
	 * 是否拥有 "纵向 粘合剂"
	 */
	public boolean hasVetAdhesive() {
		if(vetAdhesive != null)	return true;
		else					return false;
	}
	
	
	
	/**
	 * 横向黏连
	 * 
	 * @param cell : 当前的 单元格
	 * @param adhesive : 粘合剂
	 */
	public void adhereHorizontally(XSSFCell cell) {
		/*
		 * 当
		 * 1、"左一格cell" 不为 null
		 * 2、"本cell" 和 "左一格cell" 符合 粘合剂 的 "横向相等 判定"
		 * 则 进行 "横向黏连" 操作
		 */
		XSSFCell cellLeft = MergedRegionUtils.getLeftCell(cell);//左一格 cell
		
		if(cellLeft!=null && equalsHorizontally(cell, cellLeft)) {
			MergedRegionUtils.horizontalMerge(cellLeft, cell);
		}
	}

	/**
	 * 纵向黏连
	 * 
	 * @param cell : 当前的 单元格
	 * @param hizAdhesive : 粘合剂
	 */
	public void adhereVertically(XSSFCell cell) {
		/*
		 * 当
		 * 1、"上一格cell" 不为 null
		 * 2、"本cell" 和 "上一格cell" 符合 粘合剂 的 "纵向相等 判定"
		 * 则 进行 "纵向黏连" 操作
		 */
		XSSFCell cellUpper = MergedRegionUtils.getUpperCell(cell);//上一格 cell
		
		if(cellUpper!=null && equalsVertically(cell, cellUpper)) {
			MergedRegionUtils.verticalMerge(cellUpper, cell);
		}
	}
	
	
	
	
	/*--------------------------------------------
    |      			横向判等、纵向判等		         |
    ============================================*/
	
	/**
	 * 判断：2 个 cell 是否满足 "横向相等"
	 */
	public boolean equalsHorizontally(XSSFCell cell1, XSSFCell cell2) {

		List<Object> exclusionList = new ArrayList<Object>(Arrays.asList(hizAdhesive.getExclusions()));
		
		return equals(cell1, cell2, exclusionList);
	}
	
	/**
	 * 判断：2 个 cell 是否满足 "纵向相等"
	 */
	public boolean equalsVertically(XSSFCell cell1, XSSFCell cell2) {
		
		List<Object> exclusionList = new ArrayList<Object>(Arrays.asList(vetAdhesive.getExclusions()));
		
		return equals(cell1, cell2, exclusionList);
	}
	
	
	/**
	 * 粘合剂 的 "黏连规则 / 判等策略"（函数式）
	 * <br>
	 * <br> 默认：2 个 cell 所在的 "合并单元格" 的 "左上角cell" 的值 如果相同，则认为 "相等"，即 对他们进行 "合并单元格" 操作
	 * <br>
	 * <br> 自定义：开发者 可以 继承 Adhesive、重写 equals() 方法、自定义"判等策略"（所以 本方法 使用 protected 进行修饰）。
	 * <br> 例如：当 2个单元格 "背景色 相同" / "公式 相同"，则 认为 "相等"
	 * <br> 所以说 "注射器"、"样式器" 的 使用，应当在 "黏连逻辑" 之前 进行
	 */
	protected boolean equals(XSSFCell cell1, XSSFCell cell2, List<Object> exclusionList) {
		
		//TODO：代码优化，有没有什么方式，可以在 现在 exclusionList 中判断是否存在，然后直接 剔除？
		//不进 MergedRegionUtils.equals 方法
		
		return MergedRegionUtils.equals(cell1, cell2, exclusionList);
		
//		if(exclusionList.contains(cell1)) { //cell1 在 "排除列表" 中，则认为 "不相等"，即不进行 "黏连操作"
//			return false;
//			
//		}else {
//			return MergedRegionUtils.equals(cell1, cell2);
//		}
	}
	

	


	/*--------------------------------------------
    |      			2 个  构造器、1 个 打印器	     	    |
    ============================================*/
	
	/**
	 * 打印器
	 */
	@Override
	public String toString() {
		return "Adhesive [hizAdhesive=" + hizAdhesive + ", vetAdhesive=" + vetAdhesive + "]";
	}

	
	/**
	 * 构造器：
	 * <br> 参数 缺省 时，表示：
	 * <br> 1、粘合剂 在 横、纵 维度 都具有 "黏连能力"
	 * <br> 2、横、纵 维度 的 "排除列表" 都为 空数组，即 不排除 任何 项
	 */
	public Adhesive() {
		// 默认：粘合剂 在 横、纵 维度 都具有 "黏连能力"
		this(new Object[]{}, new Object[]{});
	}

	
	/**
	 * 构造器：
	 * <br> 1、通过提供 横向维度 / 纵向维度 的 "排除列表"，来表明 粘合剂 具有 该维度 的 "黏连能力" 
	 * <br> 2、如果 排除列表 为 null，则 表示 没有 该维度 的 "黏连能力"
	 * 
	 * @param hExclusions : 横向黏连 的 "排除列表"
	 * @param vExclusions : 纵向黏连 的 "排除列表"
	 */
	public Adhesive(Object[] hExclusions, Object[] vExclusions) {
		// 如果 排除列表 为 null，则 表示 没有 该维度 的 "黏连能力"
		hizAdhesive 	= hExclusions==null ? null : new Dimension(hExclusions);
		vetAdhesive 	= vExclusions==null ? null : new Dimension(vExclusions);
	}
	
	
	
	/*--------------------------------------------
    |      			getter、setter		         |
    ============================================*/
	
	public Dimension getHizAdhesive() {
		return hizAdhesive;
	}
	public void setHizAdhesive(Dimension hizAdhesive) {
		this.hizAdhesive = hizAdhesive;
	}

	public Dimension getVetAdhesive() {
		return vetAdhesive;
	}
	public void setVetAdhesive(Dimension vetAdhesive) {
		this.vetAdhesive = vetAdhesive;
	}

	

	/**
	 * 为什么 要使用 内部类 Dimension ？
	 * 
	 * 1、如果 不使用 内部类，而是 直接使用 hExclusions、vExclusions
	 * 那么，从"语义"的角度 来看，会非常奇怪：
	 * Object[] hExclusions = null			：无 水平黏连性(横向粘合能力)
	 * Object[] hExclusions = new Object[]{}：有 水平黏连性，并且 排除列表 为空
	 * 
	 * 2、如果使用了 内部类
	 * 则 "语义逻辑" 通顺：
	 * Dimension hizAdhesive = null：无 水平黏连性
	 * Object[] hExclusions = hizAdhesive.getExclusions()：有 水平黏连性，并且 排除列表 为空
	 * 
	 */
	//private Object[] hExclusions;
	//private Object[] vExclusions;
	
	
	
	
	
	
	/** ===========================================================================================  */
	
	public static void main2(String[] args) {
		Adhesive adhesive1 = new Adhesive(new Object[]{"asd"}, new Object[]{777});
		System.out.println(adhesive1);
		
		Adhesive adhesive2 = new Adhesive();
		System.out.println(adhesive2);
	}
	
	public static void main(String[] args) {
		
		List<Object> objList = new ArrayList<Object>(Arrays.asList(123, "qwe", "", new Random()));
		
		System.out.println(objList.contains(0));				//false
		System.out.println(objList.contains(123));				//true
		System.out.println(objList.contains(new Integer(123)));	//true
		System.out.println(objList.contains("qwe"));			//true
		System.out.println(objList.contains(new Random()));		//false
		
	}
	
	
	
	
}